home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Especial Multimedia
/
Especial Multimedia.iso
/
Multimed
/
Prg
/
DLLGIF.ZIP
/
GIFDECOD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-02
|
16KB
|
651 lines
/**************************************************************************
GIFDECOD.C Turn a GIF file into a Windows packed DIB
The LZW stuff in here came from CompuServe Graphics Support Forum
I've lost the original, so I cant include the original authors
comments or credit (SORRY)
See the readme.txt file for the ommissions.
John Walsh CompuServe ID 70612,1740
08 Aug 93
**************************************************************************/
#include <windows.h>
#include <fcntl.h>
#include <types.h>
#include <stat.h>
#include <stdio.h>
#include <string.h>
#include "gifdll.h"
/* a handy little macro to turn 2 BYTES into 1 WORD */
#define BYTE2WORD(a,b)((b<<8)|a)
#define ALIGN_DWORD(X)(((X)+3)/4*4)
#define OUT_OF_MEMORY -10
#define BAD_CODE_SIZE -20
#define READ_ERROR -1
#define WRITE_ERROR -2
#define OPEN_ERROR -3
#define CREATE_ERROR -4
#define MAX_CODES 4095
static int interlaced;
/* end of interlaced var's */
HANDLE FAR PASCAL _export Gif_File_To_DIB(const char*);
static int __near decoder(int);
static int __near Put_Byte_Rout(int);
static int __near out_line(BYTE *, int);
static int __near SetUpInterTable(void);
static int __near init_exp(int);
static int __near get_next_code(void);
__inline static void Bigmemmove(BYTE __huge*,LPSTR,DWORD,DWORD);
int bad_code_count;
static int curr_size; /* The current code size */
static int clear; /* Value for a clear code */
static int ending; /* Value for a ending code */
static int newcodes; /* First available code */
static int top_slot; /* Highest code for current size */
static int slot; /* Last read code */
static int navail_bytes = 0; /* # bytes left in block */
static int nbits_left = 0; /* # bits left in current byte */
static BYTE b1; /* Current byte */
static BYTE byte_buff[257]; /* Current block */
static BYTE *pbytes; /* Pointer to next byte in block */
static long code_mask[13] = {
0,
0x0001, 0x0003,
0x0007, 0x000F,
0x001F, 0x003F,
0x007F, 0x00FF,
0x01FF, 0x03FF,
0x07FF, 0x0FFF
};
static BYTE stack[MAX_CODES + 1]; /* Stack for storing pixels */
static BYTE suffix[MAX_CODES + 1]; /* Suffix table */
static WORD prefix[MAX_CODES + 1]; /* Prefix linked list */
FILE *hFile;
static HANDLE hBuf,hIntTable=NULL, hHugeBuf;
static PWORD pIntTable;
static WORD height;
static DWORD hIndex, Dwidth;
static size_t headsize;
static short lc=0;
static BYTE __huge *pHugeBuf;
/**************************************************************************
FUNCTION: HANDLE FAR PASCAL _export Gif_File_To_DIB(const char* filename)
Give this function a path/filename and it will return a handle
to a Windows packed DIB (BITMAPINFO w/RGBQUAD + Bits)
It will decode interlaced images too
**************************************************************************/
HANDLE FAR PASCAL _export Gif_File_To_DIB(const char* filename)
{
LPBITMAPINFO lpBMI;
BYTE bf;
short n,i;
WORD numents,palsize,bpp,fbpp;
WORD ll,a,b;
HANDLE hBMI;
DWORD imagesize,Bigimgsize;
struct {
char signature[3];
char version[3];
WORD width;
WORD height;
BYTE bitfield;
BYTE backcolor;
BYTE pixaspect;
}lscreen;
struct {
WORD left;
WORD top;
WORD width;
WORD height;
BYTE bitfield;
}img_desc;
hFile=fopen(filename,"rb");
if(hFile==NULL)
{MessageBox(NULL,"file opening error gifdecod",NULL,MB_ICONHAND|MB_SYSTEMMODAL);
return NULL;}
rewind(hFile);
for(i=0;i<3;i++)
lscreen.signature[i]=(char)fgetc(hFile);
for(i=0;i<3;i++)
lscreen.version[i]=(char)fgetc(hFile);
a=(WORD)fgetc(hFile);
b=(WORD)fgetc(hFile);
ll=lscreen.width=BYTE2WORD(a,b);
a=(WORD)fgetc(hFile);
b=(WORD)fgetc(hFile);
height=lscreen.height=BYTE2WORD(a,b);
lscreen.bitfield=(BYTE)fgetc(hFile);
lscreen.backcolor=(BYTE)fgetc(hFile);
lscreen.pixaspect=(BYTE)fgetc(hFile);
if(lscreen.bitfield && 128)
{
bf=(BYTE)(lscreen.bitfield<<5);
bpp=(WORD)((bf>>5)+1);
switch(bpp)
{
case 1:
fbpp=8;
break;
case 2:
case 3:
case 4:
fbpp=8;
break;
case 5:
case 6:
case 7:
case 8:
fbpp=8;
break;
}
numents=(2<< fbpp-1);
palsize=numents*(WORD)sizeof(RGBQUAD);
headsize=(size_t)sizeof(BITMAPINFOHEADER)+(size_t)palsize;
if((hBMI=GlobalAlloc(GHND,headsize))==NULL)
{MessageBox(NULL,"hBMI alloc error gif",
NULL,MB_ICONASTERISK|MB_SYSTEMMODAL);
return NULL;
}
if((lpBMI=(LPBITMAPINFO)GlobalLock(hBMI))==NULL)
{MessageBox(NULL,"Class m_hBMI Lock error gif",
NULL,MB_ICONASTERISK|MB_SYSTEMMODAL);
return NULL;
}
switch(bpp)
{
case 1:
{
lpBMI->bmiColors[0].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[0].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[0].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[0].rgbReserved=0;
lpBMI->bmiColors[1].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[1].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[1].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[1].rgbReserved=0;
break;
}
case 2:
{
for(n=0;n<4;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
case 3:
{
for(n=0;n<8;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
case 4:
{
for(n=0;n<16;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
case 5:
{
for(n=0;n<32;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
case 6:
{
for(n=0;n<64;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
case 7:
{
for(n=0;n<128;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
case 8:
{
for(n=0;n<256;n++)
{
lpBMI->bmiColors[n].rgbRed=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbGreen=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbBlue=(BYTE)fgetc(hFile);
lpBMI->bmiColors[n].rgbReserved=(BYTE)0;
}
break;
}
}
}
n=fgetc(hFile); // should be 0x2C image descriptor label
if(n!=0x2C) // but if it is'nt
while(n!=0x2C) // throw stuff away till it does
n=fgetc(hFile);// yep- no support for extensions
a=(WORD)fgetc(hFile);
b=(WORD)fgetc(hFile);
img_desc.left=BYTE2WORD(a,b);
a=(WORD)fgetc(hFile);
b=(WORD)fgetc(hFile);
img_desc.top=BYTE2WORD(a,b);
a=(WORD)fgetc(hFile);
b=(WORD)fgetc(hFile);
img_desc.width=BYTE2WORD(a,b);
a=(WORD)fgetc(hFile);
b=(WORD)fgetc(hFile);
img_desc.height=BYTE2WORD(a,b);
img_desc.bitfield=(BYTE)fgetc(hFile);
ll=img_desc.width-img_desc.left;
height=img_desc.height-img_desc.top;
interlaced=img_desc.bitfield&64;
Dwidth=(ALIGN_DWORD(ll));
imagesize=(DWORD)height*(DWORD)Dwidth;
// end of file reading stuff????
lpBMI->bmiHeader.biSize = (sizeof(BITMAPINFOHEADER));
lpBMI->bmiHeader.biWidth = (WORD)ll;
lpBMI->bmiHeader.biHeight = height;
lpBMI->bmiHeader.biPlanes =1;
lpBMI->bmiHeader.biBitCount =fbpp;
lpBMI->bmiHeader.biCompression =BI_RGB;
lpBMI->bmiHeader.biSizeImage =(DWORD)height*(DWORD)Dwidth;
lpBMI->bmiHeader.biXPelsPerMeter=0L;
lpBMI->bmiHeader.biYPelsPerMeter=0L;
lpBMI->bmiHeader.biClrUsed =0L;
lpBMI->bmiHeader.biClrImportant =(DWORD)(2<<bpp-1);
// LETS RETURN HERE IF ITS AN IMAGE QUERY
// PROCESS THE IMAGE IF ITS NOT A QUERY
/* interlaced setup routine*/
if(interlaced)
SetUpInterTable();
/* end of interlace setup*/
Bigimgsize=imagesize+(DWORD)headsize;
GlobalCompact(Bigimgsize);
if((hHugeBuf=GlobalAlloc(GHND,Bigimgsize*sizeof(BYTE)))==NULL)
{MessageBox(NULL,"memory alloc error HUGE",NULL,MB_ICONHAND|MB_SYSTEMMODAL);
return NULL;}
if((pHugeBuf=(BYTE __huge*)GlobalLock(hHugeBuf))==NULL)
{MessageBox(NULL,"memory lock error HUGE",NULL,MB_ICONHAND|MB_SYSTEMMODAL);
return NULL;}
/*******************end interlaced buffer ********************************/
_fmemcpy(pHugeBuf,lpBMI,(size_t)headsize);
hIndex=Bigimgsize-Dwidth;
n=decoder(ll);
GlobalUnlock(hHugeBuf);
fclose(hFile);
if(hIntTable!=NULL)
{
LocalUnlock(hIntTable);
LocalFree(hIntTable);
}
return hHugeBuf;
}
/****************************************************************************
Outline is easier now that we got huge
*****************************************************************************/
int __near out_line(BYTE pixels[], int linelen)
{
if(!interlaced)
{
Bigmemmove(pHugeBuf,(LPSTR)pixels,(DWORD)linelen,(DWORD)hIndex);
hIndex-=Dwidth;
}
else
{
Bigmemmove(pHugeBuf,(LPSTR)pixels,(DWORD)linelen,
((DWORD)headsize)+(DWORD)pIntTable[lc]*(DWORD)Dwidth);
lc+=1;
}
return 0;
}
static int __near init_exp(int size)
{
curr_size = size + 1;
top_slot = 1 << curr_size;
clear = 1 << size;
ending = clear + 1;
slot = newcodes = ending + 1;
navail_bytes = nbits_left = 0;
return(0);
}
static int __near get_next_code(void)
{
int i, x;
DWORD ret;
if (nbits_left == 0)
{
if (navail_bytes <= 0)
{
pbytes = byte_buff;
if ((navail_bytes = getc(hFile)) < 0)
return(navail_bytes);
else if (navail_bytes)
{
for (i = 0; i < navail_bytes; ++i)
{
if ((x = getc(hFile)) < 0)
return(x);
byte_buff[i] = (BYTE)x;
}
}
}
b1 = *pbytes++;
nbits_left = 8;
--navail_bytes;
}
ret = b1 >> (8 - nbits_left);
while (curr_size > nbits_left)
{
if (navail_bytes <= 0)
{
pbytes = byte_buff;
if ((navail_bytes = getc(hFile)) < 0)
return(navail_bytes);
else if (navail_bytes)
{
for (i = 0; i < navail_bytes; ++i)
{
if ((x = getc(hFile)) < 0)
return(x);
byte_buff[i] = (BYTE)x;
}
}
}
b1 = *pbytes++;
ret |= b1 << nbits_left;
nbits_left += 8;
--navail_bytes;
}
nbits_left -= curr_size;
ret &= code_mask[curr_size];
return((int)(ret));
}
int __near decoder(int linewidth)
{
register BYTE *sp, *bufptr;
BYTE *buf;
register int code, fc, oc, bufcnt;
int c, size, ret;
HANDLE hBuf;
if ((size = getc(hFile)) < 0)
return(size);
if (size < 2 || 9 < size)
return(BAD_CODE_SIZE);
init_exp(size);
oc = fc = 0;
if((hBuf=LocalAlloc(LMEM_MOVEABLE|LMEM_ZEROINIT,linewidth+1))==NULL)
return OUT_OF_MEMORY;
if((buf=(BYTE *)LocalLock(hBuf))==NULL)
return OUT_OF_MEMORY;
sp = stack;
bufptr = buf;
bufcnt = linewidth;
while ((c = get_next_code()) != ending)
{
if (c < 0)
{
LocalUnlock(hBuf);
LocalFree(hBuf);
return(0);
}
if (c == clear)
{
curr_size = size + 1;
slot = newcodes;
top_slot = 1 << curr_size;
while ((c = get_next_code()) == clear);
if (c == ending)
break;
if (c >= slot)
c = 0;
oc = fc = c;
*bufptr++ = (BYTE)c;
if (--bufcnt == 0)
{
if ((ret = out_line(buf, linewidth)) < 0)
{
LocalUnlock(hBuf);
LocalFree(hBuf);
return(ret);
}
bufptr = buf;
bufcnt = linewidth;
}
}
else
{
code = c;
if (code >= slot)
{
if (code > slot)
++bad_code_count;
code = oc;
*sp++ = (BYTE)fc;
}
while (code >= newcodes)
{
*sp++ = suffix[code];
code = prefix[code];
}
*sp++ = (BYTE)code;
if (slot < top_slot)
{
suffix[slot] = fc = code;
prefix[slot++] = oc;
oc = c;
}
if (slot >= top_slot)
if (curr_size < 12)
{
top_slot <<= 1;
++curr_size;
}
while (sp > stack)
{
*bufptr++ = *(--sp);
if (--bufcnt == 0)
{
if ((ret = out_line(buf, linewidth)) < 0)
{
LocalUnlock(hBuf);
LocalFree(hBuf);
return(ret);
}
bufptr = buf;
bufcnt = linewidth;
}
}
}
}
ret = 0;
if (bufcnt != linewidth)
ret = out_line(buf, (linewidth - bufcnt));
LocalUnlock(hBuf);
LocalFree(hBuf);
return(ret);
}
/*************************************************************************/
// Here we set up a tabel of Image Line Numbers so we know where to put
// the lines of an interlaced gif.
//
/*************************************************************************/
int __near SetUpInterTable(void)
{
WORD cc;
WORD ci1=0,ci2=1,ci3=1,ci4=1;
WORD p1,p2,p3,p4;
int set1=1,set2=1,set3=1,set4=1;
p1=(int)height/(WORD)8;
p2=p1;
p3=(int)height/(WORD)4;
p4=(int)height/(WORD)2;
LocalCompact(height);
if((hIntTable=LocalAlloc(LMEM_MOVEABLE|LMEM_ZEROINIT,
(height+1)*sizeof(WORD)))==NULL)
{
MessageBox(NULL,"local alloc error -interlaced gif table",
NULL,MB_ICONHAND|MB_SYSTEMMODAL);
return NULL;
}
if((pIntTable=(PWORD)LocalLock(hIntTable))==NULL)
{
MessageBox(NULL,"local lock error -interlaced gif table",
NULL,MB_ICONHAND|MB_SYSTEMMODAL);
return NULL;
}
height--;
lc=0;
for(cc=0;cc<height;cc++)
{
if(ci1<p1)
{
pIntTable[cc]=height-(WORD)(ci1*8);
ci1+=1;
}
else if(ci2<p2)
{
if(set2)
{
pIntTable[cc]=height-(WORD)4;
set2=0;
}
else
{
pIntTable[cc]=height-(WORD)(4+(ci2*8));
ci2+=1;
}
}
else if(ci3<p3)
{
if(set3)
{
pIntTable[cc]=height-(WORD)2;
set3=0;
}
else
{
pIntTable[cc]=height-(WORD)(2+(ci3*4));
ci3+=1;
}
}
else if(ci4<p4)
{
if(set4)
{
pIntTable[cc]=height-(WORD)1;
set4=0;
}
else
{
pIntTable[cc]=height-(WORD)(1+(ci4*2));
ci4+=1;
}
}
}
height++;
}
__inline void Bigmemmove(BYTE __huge*Dest,LPSTR Src,DWORD Num, DWORD spos)
{
DWORD x;
for(x=0;x<Num;x++)
Dest[spos+x]=(BYTE)Src[(short)x];
return;
}